﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using NUnit.Framework;
using Stauffware.Common.Core;

namespace UnitTests.Console
{

#if false  // TEMPORARILY DISABLED - module still under development; testcases currently broken

	public class ConCfgSet_UnitTests
	{
		#region Test Data

		public enum WriteMode
		{
			Create,
			Append,
			Replace
		}

		[CmdLineGroup()]
		public class SampleSettings1
		{
			public string Output = "old value for output";
			public WriteMode Mode = WriteMode.Append;
			public int MaxErrors = 54321;
			public bool Verbose = false;

			[CmdLineArg(Name="-iSwitch")]
			public int IntSwitch = 9;

			[CmdLineArg(Name="-bSwitch")]
			public bool BoolSwitch = false;

			public SampleSettings1 ( ) { }

			public SampleSettings1(string output, WriteMode mode, int maxErrors, bool verbose)
			{
				this.Output = output;
				this.Mode = mode;
				this.MaxErrors = maxErrors;
				this.Verbose = verbose;
			}

			///// <summary>
			///// Compares this object against another one and returns a string containing
			///// a list of differences, or null if the were the same.
			///// </summary>
			//public string CompareTo (SampleSettings1 expected)
			//{
			//    string errs = "";
			//    if (this.Output != expected.Output) errs += "\nOutput: expected " + 
			//                ErrorUtils.ValueToString(expected.Output) + ", got " +
			//                ErrorUtils.ValueToString(this.Output);

			//    if (this.Mode != expected.Mode) errs += "\nMode: expected " + 
			//                ErrorUtils.ValueToString(expected.Mode) + ", got " +
			//                ErrorUtils.ValueToString(this.Mode);

			//    if (this.MaxErrors != expected.MaxErrors) errs += "\nMaxErrors: expected " + 
			//                ErrorUtils.ValueToString(expected.MaxErrors) + ", got " +
			//                ErrorUtils.ValueToString(this.MaxErrors);

			//    if (this.Verbose != expected.Verbose) errs += "\nVerbose: expected " + 
			//                ErrorUtils.ValueToString(expected.Verbose) + ", got " +
			//                ErrorUtils.ValueToString(this.Verbose);

			//    return (errs == "") ? null : errs.Substring(1);
			//}

		}

		#endregion

		//-----------------------------------------------------------------------------

		private SampleSettings1 Settings1;
		private CmdLineParser CmdLineParser;

		//-----------------------------------------------------------------------------

		public ConCfgSet_UnitTests ( )
		{
		}

		//-----------------------------------------------------------------------------

		[TestCase("", "")]
		[TestCase("output=foo", "Output=\"foo\"")]
		[TestCase("maxErrors=17", "MaxErrors=17")]
		[TestCase("maxErrors = 23", "MaxErrors=23")]
		[TestCase("verbose=true", "Verbose=True")]
		[TestCase("mode=Create", "Mode=Create")]
		[TestCase("verbose=true mode=Replace output=foo maxErrors=42", 
				  "MaxErrors=42; Mode=Replace; Output=\"foo\"; Verbose=True")]
		[TestCase("-iswitch 999", "IntSwitch=999")]
		[TestCase("-bswitch true", "BoolSwitch=True")]
		[TestCase("-bsw false", "")]

		public void PositiveTest (string cmdLineArgs,
								  string expectedChanges)
		{
			this.Settings1 = new SampleSettings1();
			SampleSettings1 original = new SampleSettings1();

			this.CmdLineParser = new CmdLineParser(this.Settings1);

			string[] splitArgs = cmdLineArgs.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);

			this.CmdLineParser.ParseCmdLine(splitArgs);

			string changes = GetChanges(original, this.Settings1);
			NUnit.Framework.Assert.AreEqual(expectedChanges, changes);
		}

		//-----------------------------------------------------------------------------

		[TestCase("-bogusFlag", "unknown parameter name: \"-bogusFlag\"")]
		[TestCase("mode=foobar", "parameter \"Mode\" - \"foobar\" - invalid value")]

		public void NegativeTest (string cmdLineArgs, string xErrMsg)
		{
		    this.Settings1 = new SampleSettings1();
		    this.CmdLineParser = new CmdLineParser(this.Settings1);
		    string[] splitArgs = cmdLineArgs.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);

			try
			{
				this.CmdLineParser.ParseCmdLine(splitArgs);
				NUnit.Framework.Assert.Fail("expecting exception to be thrown");
			}
			catch (Stauffware.Common.Console.CmdLineSyntaxError e)
			{
				NUnit.Framework.Assert.AreEqual(xErrMsg, e.Message);
			}
		}

		//-----------------------------------------------------------------------------
		// Compares the two objects (which must be of the same type), and returns a
		// string containing a list of the field and property values in 'after' that 
		// are different from those in 'before'.  The field and property values are
		// sorted by name (ignoring case) and separated by "; ".  Each one has the
		// form: "NAME=VALUE".

		private static string GetChanges (object before, object after)
		{
			Type type = before.GetType();
			Require.Condition(type == after.GetType());

			BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | 
									BindingFlags.NonPublic | BindingFlags.DeclaredOnly;

			ListString changes = new ListString("; ");

			List<MemberInfo> members = new List<MemberInfo>(type.GetMembers(bindingFlags));
			members.Sort( (a,b) => { return string.Compare(a.Name, b.Name, true); } );

			foreach (MemberInfo mi in members)
			{
				object valueBefore;
				object valueAfter;

				if (mi is FieldInfo)
				{
					valueBefore = ((FieldInfo) mi).GetValue(before);
					valueAfter = ((FieldInfo) mi).GetValue(after);
				}
				else if (mi is PropertyInfo)
				{
					valueBefore = ((PropertyInfo)mi).GetValue(before, null);
					valueAfter = ((PropertyInfo)mi).GetValue(after, null);
				}
				else continue;	// skip other member types

				if (!object.Equals(valueBefore, valueAfter))
					changes.Add(mi.Name + "=" + ErrorUtils.ValueToString(valueAfter));
			}

			return changes.ToString();
		}

		//-----------------------------------------------------------------------------
	}

#endif
}
